#include "listener.h"
#include <assert.h>
#include <alut.h>
//#include <al.h>
#include "datatypedefine.h"
#include "transform.h"
#include <osg\Camera>

namespace OpenAudio
{
	Listener::Listener(CoreBase::Scene* sender):CoreBase::Transformable(NULL)
	{
		clear();  
		addSender(sender);
	}

	Listener::~Listener()
	{}

	void Listener::setVelocity(const osg::Vec3f& velocity)
	{
		alListener3f(AL_VELOCITY,
			static_cast<ALfloat>(velocity[0]),
			static_cast<ALfloat>(velocity[1]),
			static_cast<ALfloat>(velocity[2]));
	}

	void Listener::getVelocity(osg::Vec3f& velocity) const
	{
		alGetListener3f(AL_VELOCITY, static_cast<ALfloat*>(&velocity[0]),
			static_cast<ALfloat*>(&velocity[1]),
			static_cast<ALfloat*>(&velocity[2]));
	}

	void Listener::setGain(float gain)
	{
		gain = gain<0.0f?0.0f:gain;
		gain = gain>1.0f?1.0f:gain;
		alListenerf(AL_GAIN, gain);
	}

	float Listener::getGain(void) const
	{
		float g;
		alGetListenerf(AL_GAIN, &g);
		return g;
	}

	void Listener::onMessage(MessageData* data)
	{
		assert(data);
		if(data->message == SYSTEM_MESSAGE_FRAME)
		{
			osg::Matrix       matrix;
			if(getOSGNode()->getNumParents()>0)
			{
				osg::Node* parentnode = getOSGNode()->getParent(0);
				if(parentnode!=NULL)
				{
					osg::Camera* ca = dynamic_cast<osg::Camera*>(parentnode);
					matrix = ca->getInverseViewMatrix();
				}
				ALfloat           pos[3];
				union orient
				{
					ALfloat     ort[6];
					struct
					{
						ALfloat  at[3];
						ALfloat  up[3];
					};
				} orient;
				osg::Vec3 tmp = matrix.getTrans();
				pos[0] = tmp[0];
				pos[1] = tmp[1];
				pos[2] = tmp[2];
				orient.at[0] = matrix(1,0);
				orient.at[1] = matrix(1,1);
				orient.at[2] = matrix(1,2);
				orient.up[0] = matrix(2,0);
				orient.up[1] = matrix(2,1);
				orient.up[2] = matrix(2,2);
				alListenerfv(AL_POSITION, pos);
				alListenerfv(AL_ORIENTATION, orient.ort);
			}
		}
	}

	void Listener::clear(void)
	{
		union
		{
			ALfloat     ort[6];
			struct
			{
				ALfloat  at[3];
				ALfloat  up[3];
			};
		}  orient;
		orient.ort[0] = 0.0f;
		orient.ort[1] = 1.0f;
		orient.ort[2] = 0.0f;
		orient.ort[3] = 0.0f;
		orient.ort[4] = 0.0f;
		orient.ort[5] = 1.0f;
		ALfloat  pos[3L]  = { 0.0f, 0.0f, 0.0f };
		alListenerfv( AL_POSITION, pos );
		alListenerfv( AL_ORIENTATION, orient.ort );
		setVelocity(osg::Vec3f(0.0f, 0.0f, 0.0f));
		setGain(1.0);
	}
}